package com.linkgie.galaxyframework.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * 二进制工具类；
 * 
 * @author haiq
 *
 */
public class BinaryUtils {

	public static final String UTF8_CHARSET = "UTF-8";

	public static final byte[] EMPTY_BYTES = {};

	/**
	 * 最大缓存大小(1GB)；
	 */
	public static final int MAX_BUFFER_SIZE = 1024 * 1024 * 1024;
	
	/**
	 * 缓冲大小（4096KB）；
	 */
	public static final int BUFFER_SIZE = 4096;

	public static final byte TRUE_BYTE = 1;

	public static final byte FALSE_BYTE = 0;

	private BinaryUtils() {
	}

	public static boolean isEmpty(byte[] bytes) {
		return bytes == null || bytes.length == 0;
	}

	/**
	 * 比较指定的两个字节数组是否一致；
	 * <p>
	 * 
	 * 注：要比较的两个数组的长度都为 0 时总是返回 true;
	 * 
	 * @param bytes1 要比较的数组1；
	 * @param bytes2 要比较的数组2；
	 * @return boolean
	 */
	public static boolean equals(byte[] bytes1, byte[] bytes2) {
		if (bytes1 == bytes2) {
			return true;
		}
		if (bytes1 == null || bytes2 == null) {
			return false;
		}
		if (bytes1.length != bytes2.length) {
			return false;
		}
		for (int i = 0; i < bytes1.length; i++) {
			if (bytes1[i] != bytes2[i]) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 验证两个数组中，从指定偏移开始的相同长度的数据是否相等；
	 * <p>
	 * 
	 * 注：<br>
	 * 1. 如果要比较的两个数组中任意一个的有效长度不满足指定的长度时，返回 false；<br>
	 * 
	 * 2. 如果要比较的为 0 或小于 0 时，则引发异常 {@link IllegalArgumentException};<br>
	 * 
	 * @param bytes1  要比较的数组1；
	 * @param offset1 数组1的起始偏移量；
	 * @param bytes2  要比较的数组2；
	 * @param offset2 数组2的起始偏移量；
	 * @param length  要比较的数据的长度；
	 * @return
	 */
	public static boolean equals(byte[] bytes1, int offset1, byte[] bytes2, int offset2, int length) {
		if (bytes1 == bytes2) {
			return true;
		}
		if (bytes1 == null || bytes2 == null) {
			return false;
		}
		if (length <= 0) {
			throw new IllegalArgumentException("The length is negative or zero!");
		}
		// 验证两个数组的有效长度；
		if (bytes1.length >= (offset1 + length) && bytes2.length >= (offset2 + length)) {
			for (int i = 0; i < length; i++) {
				if (bytes1[offset1 + i] != bytes2[offset2 + i]) {
					return false;
				}
			}
			return true;
		}

		return false;
	}

	/**
	 * 将输入流复制到输出流；
	 * <p>
	 * 直到从输入流读入到缓冲区的内容为空时才中止复制；
	 * @param in
	 * @param out
	 * @return
	 * @throws IOException
	 */
	public static long copy(InputStream in, OutputStream out) throws IOException {
		byte[] buffer = new byte[BUFFER_SIZE];
		long total = 0;
		int len = 0;
		while ((len = in.read(buffer)) > 0) {
			out.write(buffer, 0, len);
			total += len;
		}
		out.flush();
		return total;
	}

	/**
	 * 将输入流复制到输出流；
	 * 
	 * @param in      输入流；
	 * @param out     输出流；
	 * @param maxSize 最大字节大小；
	 * @return 返回实际复制的字节数；
	 * @throws IOException exception
	 */
	public static int copy(InputStream in, OutputStream out, int maxSize) throws IOException {
		byte[] buffer = new byte[BUFFER_SIZE];
		int len = 0;
		int left = maxSize;
		int readLen = buffer.length;
		while (left > 0) {
			readLen = Math.min(left, buffer.length);
			len = in.read(buffer, 0, readLen);
			if (len > 0) {
				out.write(buffer, 0, len);
				left = left - len;
			} else {
				break;
			}
		}
		out.flush();
		return maxSize - left;
	}

	/**
	 * 将输入流复制到输出流；
	 * 
	 * @param in      输入流；
	 * @param out     输出流；
	 * @param maxSize 最大字节大小；
	 * @return 返回实际复制的字节数；
	 * @throws IOException exception
	 */
	public static long copy(InputStream in, OutputStream out, long maxSize) throws IOException {
		byte[] buffer = new byte[BUFFER_SIZE];
		int len = 0;
		long left = maxSize;
		int readLen = buffer.length;
		while (left > 0) {
			readLen = (int) Math.min(left, (long) buffer.length);
			len = in.read(buffer, 0, readLen);
			if (len > 0) {
				out.write(buffer, 0, len);
				left = left - len;
			} else {
				break;
			}
		}
		out.flush();
		return maxSize - left;
	}

	/**
	 * 复制从指定偏移位置开始的余下全部数据；
	 * 
	 * @param bytes
	 * @param from
	 * @return
	 */
	public static byte[] copyRange(byte[] bytes, int from) {
		return copyRange(bytes, from, bytes.length - from);
	}

	/**
	 * 复制从指定偏移位置开始的指定长度的数据；
	 * <p>
	 * 
	 * 注：此实现与 {@link Arrays#copyOfRange(byte[], int, int)}
	 * 不同，要求指定的长度不能超出原始数组的范围，返回结果一定是来源数组的子集；
	 * 
	 * @param bytes  要复制的字节数组；
	 * @param from   数据的起始偏移位置；
	 * @param length 数据的长度；必须在原始数据的有效范围之内；
	 * @return
	 */
	public static byte[] copyRange(byte[] bytes, int from, int length) {
		if (length < 0) {
			throw new IllegalArgumentException("The arg \"length\" is negative!");
		}
		if ((from + length) > bytes.length) {
			throw new IllegalArgumentException("The args \"from\" and \"length\" is out of the range of bytes!");
		}
		if (length == 0) {
			return EMPTY_BYTES;
		}
		byte[] copy = new byte[length];
		System.arraycopy(bytes, from, copy, 0, length);
		return copy;
	}

	/**
	 * 将 float 值转为4字节的二进制数组；
	 * 
	 * @param value value
	 * @return 转换后的二进制数组；
	 */
	public static byte[] toBytes(float value) {
		return toBytes(Float.floatToRawIntBits(value));
	}

	/**
	 * 将 double 值转为4字节的二进制数组；
	 * 
	 * @param value value
	 * @return 转换后的二进制数组；
	 */
	public static byte[] toBytes(double value) {
		return toBytes(Double.doubleToRawLongBits(value));
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * 
	 * @param value value
	 * @return 转换后的二进制数组，高位在前，低位在后；
	 */
	public static byte[] toBytes(int value) {
		byte[] bytes = new byte[4];
		toBytes(value, bytes, 0);
		return bytes;
	}

	public static byte[] toBytes(short value) {
		byte[] bytes = new byte[2];
		toBytes(value, bytes, 0);
		return bytes;
	}

	public static byte[] toBytes(short[] valueArray) {
		byte[] bytes = new byte[2 * valueArray.length];
		for (int i = 0; i < valueArray.length; i++) {
			toBytes(valueArray[i], bytes, i * 2);
		}
		return bytes;
	}

	public static byte[] toBytes(char value) {
		byte[] bytes = new byte[2];
		toBytes(value, bytes, 0);
		return bytes;
	}

	public static byte[] toBytes(char[] valueArray) {
		byte[] bytes = new byte[2 * valueArray.length];
		for (int i = 0; i < valueArray.length; i++) {
			toBytes(valueArray[i], bytes, i * 2);
		}
		return bytes;
	}

	public static byte[] toBytes(boolean value) {
		return new byte[] { value ? TRUE_BYTE : FALSE_BYTE };
	}

	/**
	 * 将 long 值转为8字节的二进制数组；
	 * 
	 * @param value value
	 * @return 转换后的二进制数组，高位在前，低位在后；
	 */
	public static byte[] toBytes(long value) {
		byte[] bytes = new byte[8];
		toBytes(value, bytes, 0);
		return bytes;
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * 
	 * @param value 要转换的int整数；
	 * @param bytes 要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 0 开始的4个元素；
	 */
	public static void toBytes(short value, byte[] bytes) {
		toBytes(value, bytes, 0);
	}

	public static int toBytes(int value, byte[] bytes) {
		return toBytes(value, bytes, 0);
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * <p>
	 * 以“高位在前”的方式转换，即：数值的高位保存在数组地址的低位（Big Endian 模式）；
	 * 
	 * @param value  要转换的int整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的4个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @return 返回写入的长度；
	 */
	public static int toBytes(int value, byte[] bytes, int offset) {
		return toBytes_BigEndian(value, bytes, offset);
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * <p>
	 * 以“高位在前”的方式转换，即：数值的高位保存在数组地址的低位（Big Endian 模式）；
	 * 
	 * @param value  要转换的int整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的4个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @return 返回写入的长度；
	 */
	public static int toBytes_BigEndian(int value, byte[] bytes, int offset) {
		bytes[offset] = (byte) ((value >>> 24) & 0x00FF);
		bytes[offset + 1] = (byte) ((value >>> 16) & 0x00FF);
		bytes[offset + 2] = (byte) ((value >>> 8) & 0x00FF);
		bytes[offset + 3] = (byte) (value & 0x00FF);
		return 4;
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * <p>
	 * 以“高位在后”的方式转换，即：数值的高位保存在数组地址的高位（Little Endian 模式）；
	 * 
	 * @param value  要转换的int整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的4个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @return 返回写入的长度；
	 */
	public static int toBytes_LittleEndian(int value, byte[] bytes, int offset) {
		bytes[offset] = (byte) (value & 0x00FF);
		bytes[offset + 1] = (byte) ((value >>> 8) & 0x00FF);
		bytes[offset + 2] = (byte) ((value >>> 16) & 0x00FF);
		bytes[offset + 3] = (byte) ((value >>> 24) & 0x00FF);
		return 4;
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * <p>
	 * 以“高位在后”的方式转换，即：数值的高位保存在数组地址的高位（Little Endian 模式）；
	 * 
	 * @param value  要转换的int整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的4个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @return 返回写入的长度；
	 */
	public static int toBytesInReverse(int value, byte[] bytes, int offset) {
		return toBytes_LittleEndian(value, bytes, offset);
	}

	/**
	 * 将 int 值转为4字节的二进制数组；
	 * <p>
	 * 以“高位在后”的方式转换，即：数值的高位保存在数组地址的高位；
	 * 
	 * @param value  要转换的int整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的4个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @param len    写入长度；必须大于 0 ，小于等于 4；
	 * @return 返回写入的长度；
	 */
	public static int toBytesInReverse(int value, byte[] bytes, int offset, int len) {
		int i = 0;
		int l = len > 4 ? 4 : len;
		for (; i < l; i++) {
			bytes[offset + i] = (byte) ((value >>> (8 * i)) & 0x00FF);
		}

		return i;
	}

	public static void toBytes(short value, byte[] bytes, int offset) {
		bytes[offset] = (byte) ((value >>> 8) & 0x00FF);
		bytes[offset + 1] = (byte) (value & 0x00FF);
	}

	public static void toBytes_BigEndian(short value, byte[] bytes, int offset) {
		bytes[offset] = (byte) ((value >>> 8) & 0x00FF);
		bytes[offset + 1] = (byte) (value & 0x00FF);
	}

	public static void toBytes(char value, byte[] bytes, int offset) {
		bytes[offset] = (byte) ((value >>> 8) & 0x00FF);
		bytes[offset + 1] = (byte) (value & 0x00FF);
	}

	/**
	 * 将 long 值转为8字节的二进制数组；
	 * 
	 * @param value  要转换的long整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的8个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @return 返回写入的长度；
	 */
	public static int toBytes(long value, byte[] bytes, int offset) {
		return toBytes_BigEndian(value, bytes, offset);
	}

	/**
	 * 将 long 值转为8字节的二进制数组；
	 * 
	 * @param value  要转换的long整数；
	 * @param bytes  要保存转换结果的二进制数组；转换结果将从高位至低位的顺序写入数组从 offset 指定位置开始的8个元素；
	 * @param offset 写入转换结果的起始位置；
	 * @return 返回写入的长度；
	 */
	public static int toBytes_BigEndian(long value, byte[] bytes, int offset) {
		bytes[offset] = (byte) ((value >>> 56) & 0x00FF);
		bytes[offset + 1] = (byte) ((value >>> 48) & 0x00FF);
		bytes[offset + 2] = (byte) ((value >>> 40) & 0x00FF);
		bytes[offset + 3] = (byte) ((value >>> 32) & 0x00FF);
		bytes[offset + 4] = (byte) ((value >>> 24) & 0x00FF);
		bytes[offset + 5] = (byte) ((value >>> 16) & 0x00FF);
		bytes[offset + 6] = (byte) ((value >>> 8) & 0x00FF);
		bytes[offset + 7] = (byte) (value & 0x00FF);
		return 8;
	}

	public static byte[] toBytes_UTF8(String str) {
		return toBytes(str, UTF8_CHARSET);
	}

	public static byte[] toBytes(String str, String charset) {
		if (null == str) {
			return null;
		}
		try {
			byte[] bytes = str.getBytes(charset);
			return bytes;
		} catch (UnsupportedEncodingException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static byte[] toBytes(String str, Charset charset) {
		if (null == str) {
			return null;
		}
		byte[] bytes = str.getBytes(charset);
		return bytes;
	}

	/**
	 * 以默认字符集({@value #UTF8_CHARSET})生成字符串；
	 * 
	 * @param bytes
	 * @return
	 */
	public static String toString_UTF8(byte[] bytes) {
		return toString(bytes, UTF8_CHARSET);
	}

	/**
	 * 以默认字符集({@value #UTF8_CHARSET})生成字符串；
	 * 
	 * @param bytes
	 * @param offset
	 * @return
	 */
	public static String toString(byte[] bytes, int offset) {
		return toString(bytes, offset, bytes.length - offset, UTF8_CHARSET);
	}

	/**
	 * 以默认字符集({@value #UTF8_CHARSET})生成字符串；
	 * 
	 * @param bytes
	 * @param offset
	 * @param len
	 * @return
	 */
	public static String toString(byte[] bytes, int offset, int len) {
		return toString(bytes, offset, len, UTF8_CHARSET);
	}

	/**
	 * 以指定字符集生成字符串；
	 * 
	 * @param bytes
	 * @param charset
	 * @return
	 */
	public static String toString(byte[] bytes, String charset) {
		return toString(bytes, 0, bytes.length, charset);
	}

	/**
	 * 以指定字符集生成字符串；
	 * 
	 * @param bytes
	 * @param charset
	 * @return
	 */
	public static String toString(byte[] bytes, int offset, String charset) {
		return toString(bytes, offset, bytes.length - offset, charset);
	}

	/**
	 * 以指定字符集生成字符串；
	 * 
	 * @param bytes
	 * @param charset
	 * @return
	 */
	public static String toString(byte[] bytes, Charset charset) {
		return toString(bytes, 0, bytes.length, charset);
	}

	/**
	 * 以指定字符集生成字符串；
	 * 
	 * @param bytes
	 * @param offset
	 * @param len
	 * @param charset
	 * @return
	 */
	public static String toString(byte[] bytes, int offset, int len, String charset) {
		try {
			if (bytes == null) {
				return null;
			}
			if (len == 0) {
				return "";
			}
			return new String(bytes, offset, len, charset);
		} catch (UnsupportedEncodingException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	/**
	 * 以指定字符集生成字符串；
	 * 
	 * @param bytes
	 * @param offset
	 * @param len
	 * @param charset
	 * @return
	 */
	public static String toString(byte[] bytes, int offset, int len, Charset charset) {
		if (bytes == null) {
			return null;
		}
		if (len == 0) {
			return "";
		}
		return new String(bytes, offset, len, charset);
	}

	/**
	 * 以指定字符集生成字符串；
	 * 
	 * @param bytes
	 * @param offset
	 * @param len
	 * @param charset
	 * @return
	 */
	public static String toInternString(byte[] bytes, int offset, int len, String charset) {
		try {
			if (bytes == null) {
				return null;
			}
			if (len == 0) {
				return "";
			}
			return new String(bytes, offset, len, charset).intern();
		} catch (UnsupportedEncodingException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static boolean toBoolean(byte value) {
		return value != FALSE_BYTE;
	}

	/**
	 * 将字节数组的第一个字节转为 boolean 值；
	 * 
	 * @param value
	 * @return
	 */
	public static boolean toBoolean(byte[] value) {
		return value[0] != FALSE_BYTE;
	}

	/**
	 * 将字节数组指定位置开始的第一个字节转为 boolean 值；
	 * 
	 * @param value
	 * @param offset
	 * @return
	 */
	public static boolean toBoolean(byte[] value, int offset) {
		return value[offset] != FALSE_BYTE;
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从位置 0 开始的 4 个字节转换为 int 整数；
	 * 
	 * @param bytes 要转换的二进制数组；
	 * @return 转换后的 int 整数；
	 */
	public static int toInt(byte[] bytes) {
		return toInt(bytes, 0);
		// value = (value | (bytes[0] & 0xFF)) << 8;
		// value = (value | (bytes[1] & 0xFF)) << 8;
		// value = (value | (bytes[2] & 0xFF)) << 8;
		// value = value | (bytes[3] & 0xFF);
		//
		// return value;
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 2 个字节转换为 short 整数；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置
	 * @return 转换后的 short 整数；
	 */
	public static short toShort(byte[] bytes, int offset) {
		short value = 0;
		value = (short) ((value | (bytes[offset] & 0xFF)) << 8);
		value = (short) (value | (bytes[offset + 1] & 0xFF));

		return value;
	}

	public static short toShort(byte[] bytes) {
		return toShort(bytes, 0);
	}

	public static char toChar(byte[] bytes) {
		return toChar(bytes, 0);
	}

	public static char toChar(byte[] bytes, int offset) {
		char value = 0;
		value = (char) ((value | (bytes[offset] & 0xFF)) << 8);
		value = (char) (value | (bytes[offset + 1] & 0xFF));

		return value;
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 8 个字节转换为 double 浮点数； 如果位数不足将引发异常；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置，将依次读取 8 位；
	 * @return 转换后的 double 浮点数；
	 */
	public static double toDouble(byte[] bytes) {
		return toDouble(bytes, 0);
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 8 个字节转换为 double 浮点数； 如果位数不足将引发异常；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置，将依次读取 8 位；
	 * @return 转换后的 double 浮点数；
	 */
	public static double toDouble(byte[] bytes, int offset) {
		long value = toLong(bytes, offset);
		return Double.longBitsToDouble(value);
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 4 个字节转换为 float 浮点数； 如果位数不足将引发异常；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置，将依次读取 4 位；
	 * @return 转换后的 float 浮点数；
	 */
	public static float toFloat(byte[] bytes) {
		return toFloat(bytes, 0);
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 4 个字节转换为 float 浮点数； 如果位数不足将引发异常；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置，将依次读取 4 位；
	 * @return 转换后的 float 浮点数；
	 */
	public static float toFloat(byte[] bytes, int offset) {
		int value = toInt(bytes, offset);
		return Float.intBitsToFloat(value);
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 4 个字节转换为 int 整数；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置
	 * @return 转换后的 int 整数；
	 */
	public static int toInt(byte[] bytes, int offset) {
		// int value = 0;
		// value = (value | (bytes[offset] & 0xFF)) << 8;
		// value = (value | (bytes[offset + 1] & 0xFF)) << 8;
		// value = (value | (bytes[offset + 2] & 0xFF)) << 8;
		// value = value | (bytes[offset + 3] & 0xFF);
		//
		// return value;
		return toInt(bytes, offset, 4);
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 4 个字节转换为 int 整数；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置
	 * @param len    长度；len 必须满足： len 大于等于 0 且小于等于4；
	 * @return 转换后的 int 整数；
	 */
	public static int toInt(byte[] bytes, int offset, int len) {
		if (len < 0 || len > 4) {
			throw new IllegalArgumentException("Len less than 0 or greate than 4!");
		}
		int value = 0;
		for (int i = 0; i < len; i++) {
			value = value | ((bytes[offset + i] & 0xFF) << (8 * (len - 1 - i)));
		}

		return value;
	}

	public static long toLong(byte[] bytes) {
		return toLong(bytes, 0);
	}

	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 8个字节转换为 long 整数；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置
	 * @return 转换后的 long 整数；
	 */
	public static long toLong(byte[] bytes, int offset) {
		long value = 0;
		value = (value | (bytes[offset] & 0xFF)) << 8;
		value = (value | (bytes[offset + 1] & 0xFF)) << 8;
		value = (value | (bytes[offset + 2] & 0xFF)) << 8;
		value = (value | (bytes[offset + 3] & 0xFF)) << 8;
		value = (value | (bytes[offset + 4] & 0xFF)) << 8;
		value = (value | (bytes[offset + 5] & 0xFF)) << 8;
		value = (value | (bytes[offset + 6] & 0xFF)) << 8;
		value = value | (bytes[offset + 7] & 0xFF);

		return value;
	}

	
	/**
	 * 按从高位到低位的顺序将指定二进制数组从 offset 参数指定的位置开始的 8 个字节转换为 long 整数；
	 * 
	 * @param bytes  要转换的二进制数组；
	 * @param offset 要读取数据的开始位置
	 * @param len    长度；len 必须满足： len 大于等于 0 且小于等于8；
	 * @return 转换后的 int 整数；
	 */
	public static long toLong(byte[] bytes, int offset, int len) {
		if (len < 0 || len > 8) {
			throw new IllegalArgumentException("Len less than 0 or greate than 8!");
		}
		long value = 0L;
		for (int i = 0; i < len; i++) {
			value = value | ((bytes[offset + i] & 0xFFL) << (8 * (len - 1 - i)));
		}

		return value;
	}

	/**
	 * 以输入流的方式读取指定的字节数组;
	 * 
	 * @param bytes
	 * @return
	 */
	public static InputStream inputFrom(byte[] bytes) {
		return new ByteArrayInputStream(bytes);
	}

	public static byte readByte(InputStream in) {
		try {
			int value = in.read();
			if (value < 0) {
				throw new IOStatusException("No byte to read from the input stream!");
			}
			return (byte) value;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	/**
	 * 从指定的输入流中读入2个字节，由前到后按由高位到低位的方式转为 short 整数；
	 * 
	 * @param in in
	 * @return short
	 */
	public static short readShort(InputStream in) {
		try {
			int v = in.read();
			if (v < 0) {
				throw new IOStatusException("No enough data to read as short from the specified input stream!");
			}
			int value = (v & 0xFF) << 8;

			v = in.read();
			if (v < 0) {
				throw new IOStatusException("No enough data to read as short from the specified input stream!");
			}
			value = value | (v & 0xFF);
			return (short) value;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static int writeShort(short value, OutputStream out) {
		try {
			out.write((value >>> 8) & 0x00FF);
			out.write(value & 0x00FF);
			return 2;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	/**
	 * 从指定的输入流中读入4个字节，由前到后按由高位到低位的方式转为 int 整数；
	 * 
	 * @param in in
	 * @return int
	 */
	public static int readInt(InputStream in) {
		try {
			int value = 0;
			int v0 = in.read();
			int v1 = in.read();
			int v2 = in.read();
			int v3 = in.read();
			if (v0 < 0 || v1 < 0 || v2 < 0 || v3 < 0) {
				throw new IOStatusException("No enough data to read as integer from the specified input stream!");
			}
			value = (v0 << 24) | (v1 << 16) | (v2 << 8) | v3;
			return value;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static int writeInt(int value, OutputStream out) {
		try {
			out.write((value >>> 24) & 0x00FF);
			out.write((value >>> 16) & 0x00FF);
			out.write((value >>> 8) & 0x00FF);
			out.write(value & 0x00FF);
			return 4;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static long readLong(InputStream in) {
		try {
			long value = 0;
			int v;
			for (int i = 0; i < 7; i++) {
				v = in.read();
				if (v < 0) {
					throw new IOStatusException(
							"No enough data to read as long integer from the specified input stream!");
				}
				value = (value | (v & 0xFF)) << 8;
			}
			value = value | (in.read() & 0xFF);

			return value;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static int writeLong(long value, OutputStream out) {
		try {
			out.write((int) ((value >>> 56) & 0x00FF));
			out.write((int) ((value >>> 48) & 0x00FF));
			out.write((int) ((value >>> 40) & 0x00FF));
			out.write((int) ((value >>> 32) & 0x00FF));
			out.write((int) ((value >>> 24) & 0x00FF));
			out.write((int) ((value >>> 16) & 0x00FF));
			out.write((int) ((value >>> 8) & 0x00FF));
			out.write((int) (value & 0x00FF));
			return 8;
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	/**
	 * 将输入流全部读取到内存，返回对应的字节数组；
	 * <p>
	 * 注：此方法不做内存空间管理，如果输入流过大，会尝试创建相应的内存空间，并可能导致内存溢出；
	 * 
	 * @param in
	 * @return
	 */
	public static byte[] readBytes(InputStream in) {
		ByteArrayOutputStream outStream = new ByteArrayOutputStream();
		try {
			byte[] buffer = new byte[BUFFER_SIZE];
			int len = -1;
			while ((len = in.read(buffer)) != -1) {
				outStream.write(buffer, 0, len);
			}
			outStream.close();
			return outStream.toByteArray();
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static void writeByte(byte value, OutputStream out) {
		try {
			out.write(value);
		} catch (IOException e) {
			throw new IOStatusException(e.getMessage(), e);
		}
	}

	public static byte[] concat(byte[]... bytesList) {
		int size = 0;
		for (byte[] bs : bytesList) {
			size += bs.length;
		}
		byte[] bytesAll = new byte[size];
		size = 0;
		for (byte[] bs : bytesList) {
			System.arraycopy(bs, 0, bytesAll, size, bs.length);
			size += bs.length;
		}

		return bytesAll;
	}

	public static char[] concat(char[]... bytesList) {
		int size = 0;
		for (char[] bs : bytesList) {
			size += bs.length;
		}
		char[] bytesAll = new char[size];
		size = 0;
		for (char[] bs : bytesList) {
			System.arraycopy(bs, 0, bytesAll, size, bs.length);
			size += bs.length;
		}

		return bytesAll;
	}

	/**
	 * 生成安全的随机数；
	 * 
	 * @param length 输出的随机数的字节长度；
	 * @return
	 */
	public static byte[] generateRandom(int length) {
		return generateRandom(null, length);
	}

	/**
	 * 生成安全的随机数；
	 * <p>
	 * 
	 * @param seed   随机数种子；
	 * @param length 输出的随机数的字节长度；
	 * @return
	 */
	public static byte[] generateRandom(byte[] seed, int length) {
		SecureRandom sr = null;
		if (seed == null || seed.length == 0) {
			// 随机；
			sr = new SecureRandom();
		} else {
			sr = new SecureRandom(seed);
		}
		byte[] randomBytes = new byte[length];
		sr.nextBytes(randomBytes);
		return randomBytes;
	}

	/**
	 * 返回字节数组中匹配指定的作为分隔符的字节序列的起始位置；
	 * <p>
	 * 
	 * @param bytes   要查找的字节序列；
	 * @param pattern 匹配模式的字节序列；
	 * @return 返回匹配 pattern 的首个字节的位置；如果没有匹配，则返回 -1 ； 如果 bytes 或 pattern 为 null 或者长度为
	 *         0 ，则返回 -1 ；
	 */
	public static int indexOf(byte[] bytes, byte[] pattern) {
		if (bytes == null || bytes.length == 0) {
			return -1;
		}
		if (pattern == null || pattern.length == 0) {
			return -1;
		}
		int searchLength = bytes.length - pattern.length + 1;
		for (int i = 0; i < searchLength; i++) {
			if (bytes[i] == pattern[0]) {
				if (equals(bytes, i, pattern, 0, pattern.length)) {
					return i;
				}
			}
		}
		return -1;
	}

	/**
	 * 返回字节数组中匹配指定的作为分隔符的字节序列的起始位置；
	 * 
	 * @param bytes     要查找的字节序列；
	 * @param fromIndex 查找的起始位置；
	 * @param pattern   匹配模式的字节序列；
	 * @return 返回匹配 pattern 的首个字节的位置；如果没有匹配，则返回 -1 ； 如果 bytes 或 pattern 为 null 或者长度为
	 *         0 ，则返回 -1 ；
	 */
	public static int indexOf(byte[] bytes, int fromIndex, byte[] pattern) {
		if (bytes == null || bytes.length == 0) {
			return -1;
		}
		if (pattern == null || pattern.length == 0) {
			return -1;
		}
		int searchLength = (bytes.length - fromIndex) - pattern.length + 1;
		for (int i = 0; i < searchLength; i++) {
			if (bytes[fromIndex + i] == pattern[0]) {
				if (equals(bytes, fromIndex + i, pattern, 0, pattern.length)) {
					return fromIndex + i;
				}
			}
		}
		return -1;
	}

	public static byte[] serialize(Object object) throws IOException {
		if (object == null) {
			return EMPTY_BYTES;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		serialize(object, out);
		return out.toByteArray();
	}

	public static void serialize(Object object, OutputStream out) throws IOException {
		if (object == null) {
			return;
		}
		ObjectOutputStream objOut = new ObjectOutputStream(out);
		objOut.writeObject(object);
		objOut.flush();
	}

	public static <T> T deserialize(byte[] bytes) throws IOException {
		if (bytes == null || bytes.length == 0) {
			return null;
		}
		ByteArrayInputStream in = new ByteArrayInputStream(bytes);
		return deserialize(in);
	}

	public static <T> T deserialize(byte[] bytes, int offset, int length) throws IOException {
		if (bytes == null || bytes.length == 0) {
			return null;
		}
		ByteArrayInputStream in = new ByteArrayInputStream(bytes, offset, length);
		return deserialize(in);
	}

	@SuppressWarnings("unchecked")
	public static <T> T deserialize(InputStream in) throws IOException {
		try {
			try (FilteredObjectInputStream objIn = new FilteredObjectInputStream(in)) {
				Object obj = objIn.readObject();
				return (T) obj;
			}
		} catch (ClassNotFoundException e) {
			throw new IllegalStateException(e.getMessage(), e);
		}
	}

	/**
	 * 反序列化；
	 * 
	 * @param <T>
	 * @param in                  输入流；
	 * @param forbiddenClassNames 禁止反序列化创建的类名清单；通常出于安全考虑时，通过此参数指定某些类型不允许通过序列化方式创建；
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public static <T> T deserialize(InputStream in, String... forbiddenClassNames) throws IOException {
		try {
			try (FilteredObjectInputStream objIn = new FilteredObjectInputStream(in,
					CollectionUtils.toList(forbiddenClassNames))) {
				Object obj = objIn.readObject();
				return (T) obj;
			}
		} catch (ClassNotFoundException e) {
			throw new IllegalStateException(e.getMessage(), e);
		}
	}

	/**
	 * 反序列化；
	 * 
	 * @param <T>
	 * @param in                  输入流；
	 * @param forbiddenClassNames 禁止反序列化创建的类名清单；通常出于安全考虑时，通过此参数指定某些类型不允许通过序列化方式创建；
	 * @return
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public static <T> T deserialize(InputStream in, Collection<String> forbiddenClassNames) throws IOException {
		try {
			try (FilteredObjectInputStream objIn = new FilteredObjectInputStream(in, forbiddenClassNames)) {
				Object obj = objIn.readObject();
				return (T) obj;
			}
		} catch (ClassNotFoundException e) {
			throw new IllegalStateException(e.getMessage(), e);
		}
	}

	public static <T> T serializedCopy(T obj) throws IOException {
		byte[] bts = serialize(obj);
		return deserialize(bts);
	}

	public static class FilteredObjectInputStream extends ObjectInputStream {

		private final Set<String> forbiddenClasses = new HashSet<String>();

		/**
		 * 把指定类型加入禁止反序列化的类型黑名单；
		 * 
		 * @param className
		 */
		public void forbid(String className) {
			forbiddenClasses.add(className);
		}

		public FilteredObjectInputStream(InputStream in) throws IOException {
			super(in);
		}

		public FilteredObjectInputStream(InputStream in, Collection<String> forbiddenClasses) throws IOException {
			super(in);
			this.forbiddenClasses.addAll(forbiddenClasses);
		}

		@Override
		protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
			if (forbiddenClasses.contains(desc.getName())) {
				throw new SecurityException(
						"Class[" + desc.getName() + "] is forbidden to deserialize because it is in the blacklist!");
			}
			return super.resolveClass(desc);
		}

	}

}
